package com.smugmugsoftware.airconcalc.advanced;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.GetChars;
import android.view.View;
import android.widget.TextView;

public class Room implements Comparable<Room>, Parcelable, Serializable {

	private static final long serialVersionUID = 1000L;

	private Building parent;

	private long id;
	private String name;
	private int zone;

	private Vector<Wall> walls;
	private Vector<WindowDoor> windowsDoors;
	private Vector<CeilingFloor> ceilingsFloors;
	private Vector<SensibleLoad> sensibleLoads;
	
	private String BTUString;

	public Room(long id, Building parent) {
		this.id = id;
		this.parent = parent;

		name = "";
		walls = new Vector<Wall>();
		windowsDoors = new Vector<WindowDoor>();
		ceilingsFloors = new Vector<CeilingFloor>();
		sensibleLoads = new Vector<SensibleLoad>();
		zone = 1;
	}

	public void setParent(Building newParent) {
		this.parent = newParent;
	}

	public void addWall(Wall wall) {
		this.walls.add(wall);
	}

	public Wall getNewWall() {
		return new Wall(walls.size() + 1);
	}

	public void addWindowDoor(WindowDoor windowDoor) {
		this.windowsDoors.add(windowDoor);
	}

	public WindowDoor getNewWindowDoor() {
		return new WindowDoor(walls.size() + 1);
	}

	public WindowDoor getNewWindowDoor(int type) {
		return new WindowDoor(windowsDoors.size() + 1, type);
	}

	public void addCeilingFloor(CeilingFloor ceilingFloor) {
		this.ceilingsFloors.add(ceilingFloor);
	}

	public CeilingFloor getNewCeilingFloor() {
		return new CeilingFloor(ceilingsFloors.size() + 1);
	}

	public void addSensibleLoad(SensibleLoad sensibleLoad) {
		this.sensibleLoads.add(sensibleLoad);
	}

	public SensibleLoad getNewSensibleLoad(int type) {
		return new SensibleLoad(sensibleLoads.size() + 1, type);
	}

	public SensibleLoad getNewSensibleLoad(int type, String constNo) {
		return new SensibleLoad(sensibleLoads.size() + 1, type, constNo);
	}

	public Vector<Wall> getWalls() {
		return walls;
	}

	public void setWalls(Vector<Wall> walls) {
		this.walls = walls;
	}

	public Vector<WindowDoor> getWindowsDoors() {
		return windowsDoors;
	}

	public void setWindowsDoors(Vector<WindowDoor> windowsDoors) {
		this.windowsDoors = windowsDoors;
	}

	public Vector<CeilingFloor> getCeilingsFloors() {
		return ceilingsFloors;
	}

	public void setCeilingsFloors(Vector<CeilingFloor> ceilingsFloors) {
		this.ceilingsFloors = ceilingsFloors;
	}

	public void setSensibleLoads(Vector<SensibleLoad> sensibleLoads) {
		this.sensibleLoads = sensibleLoads;
	}

	public Vector<SensibleLoad> getSensibleLoads() {
		return sensibleLoads;
	}

	public void removeWall(long id) {
		Iterator<Wall> iterator = walls.iterator();
		Wall thisWall = null;
		while (iterator.hasNext()) {
			thisWall = iterator.next();

			if (thisWall.getID() == id + 1) {
				iterator.remove();
				break;
			}
		}

		Collections.sort(walls);

		for (int i = 0; i < walls.size(); i++) {
			walls.get(i).setID((long) (i + 1));
		}
	}

	public void removeCelFloor(long id) {
		Iterator<CeilingFloor> iterator = ceilingsFloors.iterator();
		CeilingFloor thisCelFloor = null;
		while (iterator.hasNext()) {
			thisCelFloor = iterator.next();

			if (thisCelFloor.getID() == id + 1) {
				iterator.remove();
				break;
			}
		}

		Collections.sort(ceilingsFloors);
		
		for (int i = 0; i < ceilingsFloors.size(); i++) {
			ceilingsFloors.get(i).setID((long) (i + 1));
		}
	}

	public void removeWinDoor(long id) {
		Iterator<WindowDoor> iterator = windowsDoors.iterator();
		WindowDoor thisWinDoor = null;
		while (iterator.hasNext()) {
			thisWinDoor = iterator.next();

			if (thisWinDoor.getID() == id + 1) {
				iterator.remove();
				break;
			}
		}

		Collections.sort(windowsDoors);

		for (int i = 0; i < windowsDoors.size(); i++) {
			windowsDoors.get(i).setID((long) (i + 1));
		}
	}

	public void removeSensibleLoad(long id) {
		Iterator<SensibleLoad> iterator = sensibleLoads.iterator();
		SensibleLoad thisSensibleLoad = null;
		while (iterator.hasNext()) {
			thisSensibleLoad = iterator.next();

			if (thisSensibleLoad.getID() == (id + 1)) {
				iterator.remove();
				break;
			}
		}

		Collections.sort(sensibleLoads);

		for (int i = 0; i < sensibleLoads.size(); i++) {
			sensibleLoads.get(i).setID((long) (i + 1));
		}
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getZone() {
		return zone;
	}

	public void setZone(int zone) {
		this.zone = zone;
	}
	
	public double[] getRoomLoadBySource(Context context) {
		TableParser parser = new TableParser(context, R.raw.heatgain);
		int column = getColumnNumber(parent.getLocaleData());
		int windowColumn = getWindowColumnNumber(parent.getLocaleData());
		
		double totalWallBTU = 0;
		double totalWindowBTU = 0;
		double totalDoorBTU = 0;
		double totalCeilingBTU = 0;
		double totalFloorBTU = 0;
		double totalSensibleBTU = 0;
		double totalInfiltrationBTU = 0;
		
		Room thisRoom = null;
		Wall thisWall = null;
		WindowDoor thisWindowDoor = null;
		CeilingFloor thisCeilingFloor = null;
		SensibleLoad thisSensibleLoad = null;

		Iterator<Wall> wallIterator = null;
		
		Iterator<WindowDoor> winDoorIterator = null;
		Vector<WindowDoor> windowVector = new Vector<WindowDoor>();
		Vector<WindowDoor> doorVector = new Vector<WindowDoor>();
		Iterator<WindowDoor> windowIterator = null;
		Iterator<WindowDoor> doorIterator = null;

		Iterator<CeilingFloor> celFloorIterator = null;
		Vector<CeilingFloor> ceilingVector = new Vector<CeilingFloor>();
		Vector<CeilingFloor> floorVector = new Vector<CeilingFloor>();
		Iterator<CeilingFloor> ceilingIterator = null;
		Iterator<CeilingFloor> floorIterator = null;
		
		Iterator<SensibleLoad> sensibleIterator = null;
		
		double thisWallArea = 0;
		double thisWallBTU = 0;
		double wallBTUMultiplier;

		int thisWindowUnshadedArea = 0;
		int thisWindowShadedArea = 0;
		double thisWindowBTU = 0;
		double windowBTUMultiplier = 0;
		String shadeString = "";
		char newChar = ' ';

		double thisDoorArea = 0;
		double thisDoorBTU = 0;
		double doorBTUMultiplier = 0;
		
		double ceilingFloorBTUMultiplier = 0;

		double totalWallLength = 0;
		double totalWallHeight = 0;
		double airChangeMultiplier = 0;
		double airChangesPerHour = 0;
		double totalRoomArea = 0;
		double totalBuildingVolume = 0;
		double totalInfiltrationCFM = 0;
		double tempDifference = 0;

			windowVector = new Vector<WindowDoor>();
			doorVector = new Vector<WindowDoor>();
			ceilingVector = new Vector<CeilingFloor>();
			floorVector = new Vector<CeilingFloor>();

			wallIterator = walls.iterator();
			winDoorIterator= windowsDoors.iterator();
			while (winDoorIterator.hasNext()) {
				thisWindowDoor = winDoorIterator.next();
				
				if (thisWindowDoor.isAWindow()) {
					windowVector.add(thisWindowDoor);
				} else if (!thisWindowDoor.isAWindow()) {
					doorVector.add(thisWindowDoor);
				}
			}
			windowIterator = windowVector.iterator();
			doorIterator = doorVector.iterator();
			
			celFloorIterator = ceilingsFloors.iterator();
			while (celFloorIterator.hasNext()) {
				thisCeilingFloor = celFloorIterator.next();
				
				if (thisCeilingFloor.isACeiling()) {
					ceilingVector.add(thisCeilingFloor);
				} else if (!thisCeilingFloor.isACeiling()) {
					floorVector.add(thisCeilingFloor);
				}
			}
			ceilingIterator = ceilingVector.iterator();
			floorIterator = floorVector.iterator();

			sensibleIterator = sensibleLoads.iterator();
			
			while (wallIterator.hasNext()) {
				thisWall = wallIterator.next();

				thisWallArea = thisWall.getArea();
				
				totalWallLength = totalWallLength + thisWall.getLengthMajorUnit() + (thisWall.getLengthMinorUnit() / 12);
				if (totalWallHeight == 0) {
					totalWallHeight = totalWallHeight + thisWall.getHeightMajorUnit() + (thisWall.getHeightMinorUnit() / 12);
				} else {
					totalWallHeight = totalWallHeight + thisWall.getHeightMajorUnit() + (thisWall.getHeightMinorUnit() / 12);
					totalWallHeight = totalWallHeight / 2;					
				}

				wallBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisWall.getConstructionNumber(), "Walls", column));

				for (WindowDoor checkWindowDoor : windowVector) {
					if (checkWindowDoor.getFacing() == thisWall.getFacing()) {
						thisWallArea = (int) (thisWallArea - checkWindowDoor.getAreaInFeet());
					}
				}

				thisWallBTU = thisWallArea * wallBTUMultiplier;
				totalWallBTU = totalWallBTU + thisWallBTU;

			}
			
			while (windowIterator.hasNext()) {
				thisWindowDoor = windowIterator.next();
				thisWindowBTU = 0;
								
				thisWindowUnshadedArea = (int) (thisWindowDoor.getAreaInFeet() - thisWindowDoor.getShadedAreaInFeet());
				thisWindowShadedArea = (int) thisWindowDoor.getShadedAreaInFeet();

				if (thisWindowShadedArea > 0) {

					for (int i = 0; i < thisWindowDoor.getConstructionNumber().length(); i++) {
						newChar = thisWindowDoor.getConstructionNumber().charAt(i);

						if (i == 1) {
							newChar = 'A';
						}

						if (i == 4) {
							newChar = 'a';
						}

						shadeString = shadeString + newChar;
					}

					shadeString = shadeString + "-A";

					windowBTUMultiplier = Double.parseDouble(parser.getDataPoint(shadeString, "Windows & Doors", windowColumn));
					thisWindowBTU = thisWindowBTU + (thisWindowShadedArea * windowBTUMultiplier); 
					shadeString = "";
				}

				windowBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisWindowDoor.getConstructionNumber() 
						+ "-" + thisWindowDoor.getFacingString(), "Windows & Doors", windowColumn));
				thisWindowBTU = thisWindowBTU + (thisWindowUnshadedArea * windowBTUMultiplier);
				totalWindowBTU = totalWindowBTU + (thisWindowBTU * thisWindowDoor.getQty());
				
			}
			
			while (doorIterator.hasNext()) {
				thisWindowDoor = doorIterator.next();
				
				thisDoorArea = thisWindowDoor.getAreaInFeet();

				windowBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisWindowDoor.getConstructionNumber(), "Windows & Doors", column));
				thisDoorBTU = thisDoorArea * doorBTUMultiplier;
				totalDoorBTU = totalDoorBTU + (thisDoorBTU * thisWindowDoor.getQty());
				
			}
			
			while (ceilingIterator.hasNext()) {
				thisCeilingFloor = ceilingIterator.next();
				
				ceilingFloorBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisCeilingFloor.getConstructionNumber(), "Ceilings & Floors", column));
				totalCeilingBTU = totalCeilingBTU + (thisCeilingFloor.getArea() * ceilingFloorBTUMultiplier);
			}
			
			while (floorIterator.hasNext()) {
				thisCeilingFloor = floorIterator.next();
				
				ceilingFloorBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisCeilingFloor.getConstructionNumber(), "Ceilings & Floors", column));
				totalFloorBTU = totalFloorBTU + (thisCeilingFloor.getArea() * ceilingFloorBTUMultiplier);
			}
			
			while (sensibleIterator.hasNext()) {
				thisSensibleLoad = sensibleIterator.next();

				totalSensibleBTU = totalSensibleBTU + (thisSensibleLoad.getBtu() * thisSensibleLoad.getQty());
			}
			
			totalRoomArea = (((totalWallLength / 4) + (totalWallLength / 16)) * ((totalWallLength / 4) - (totalWallLength / 16)));
			
			if (parent.getConstructionTightness() == Building.TIGHTNESS_BEST) {
				airChangesPerHour = airChangesPerHour + 0.2;
			} else if (parent.getConstructionTightness() == Building.TIGHTNESS_AVERAGE) {
				if (totalRoomArea <= 1500) {
					airChangesPerHour = airChangesPerHour + 0.5;
				} else {
					airChangesPerHour = airChangesPerHour + 0.4;
				}
			} else if (parent.getConstructionTightness() == Building.TIGHTNESS_LOOSE) {
				if (totalRoomArea <= 900) {
					airChangesPerHour = airChangesPerHour + 0.8;
				} else if (totalRoomArea > 900 && totalRoomArea <= 1500) {
					airChangesPerHour = airChangesPerHour + 0.7;
				} else if (totalRoomArea > 1500 && totalRoomArea <= 2100) {
					airChangesPerHour = airChangesPerHour + 0.6;
				} else if (totalRoomArea > 2100) {
					airChangesPerHour = airChangesPerHour + 0.5;
				}
			} else {
				airChangesPerHour = airChangesPerHour + 0.4;
			}
			
			airChangeMultiplier = airChangeMultiplier + airChangesPerHour;
			totalBuildingVolume = totalRoomArea * totalWallHeight;
			
			totalInfiltrationCFM = totalBuildingVolume * airChangeMultiplier * 0.0167;
			tempDifference = parent.getSummerExternalDryBulb() - parent.getSummerDesignTemp();
			totalInfiltrationBTU = totalInfiltrationCFM * tempDifference * 1.1;		

			return new double[] { totalWallBTU, totalWindowBTU, totalDoorBTU, totalCeilingBTU, totalFloorBTU, totalSensibleBTU, totalInfiltrationBTU };
	}

	public double getTotalRoomLoad(Context context) {

		TableParser parser = new TableParser(context, R.raw.heatgain);

		int thisWallArea = 0;
		int totalWallBTU = 0;
		double thisWallBTU = 0;
		double wallBTUMultiplier;

		int column = getColumnNumber(parent.getLocaleData());

		for (Wall thisWall : walls) {
			thisWallArea = (int) thisWall.getArea();
			wallBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisWall.getConstructionNumber(), "Walls", column));

			for (WindowDoor thisWindowDoor : windowsDoors) {
				if (thisWindowDoor.getFacing() == thisWall.getFacing()) {
					thisWallArea = (int) (thisWallArea - thisWindowDoor.getAreaInFeet());
				}
			}

			thisWallBTU = thisWallArea * wallBTUMultiplier;
			totalWallBTU = (int) (totalWallBTU + thisWallBTU);
		}

		int thisWindowUnshadedArea = 0;
		int thisWindowShadedArea = 0;
		int totalWindowBTU = 0;
		double thisWindowBTU = 0;
		double windowBTUMultiplier = 0;
		String shadeString = "";
		char newChar = ' ';

		int windowColumn = getWindowColumnNumber(parent.getLocaleData());

		for (WindowDoor thisWindowDoor : windowsDoors) {
			
			thisWindowBTU = 0;

			thisWindowUnshadedArea = (int) (thisWindowDoor.getAreaInFeet() - thisWindowDoor.getShadedAreaInFeet());
			thisWindowShadedArea = (int) thisWindowDoor.getShadedAreaInFeet();

			if (thisWindowShadedArea > 0 && thisWindowDoor.isAWindow()) {

				for (int i = 0; i < thisWindowDoor.getConstructionNumber().length(); i++) {
					newChar = thisWindowDoor.getConstructionNumber().charAt(i);

					if (i == 1) {
						newChar = 'A';
					}

					if (i == 4) {
						newChar = 'a';
					}

					shadeString = shadeString + newChar;
				}

				shadeString = shadeString + "-A";

				windowBTUMultiplier = Double.parseDouble(parser.getDataPoint(shadeString, "Windows & Doors", windowColumn));
				thisWindowBTU = thisWindowBTU + (thisWindowShadedArea * windowBTUMultiplier); 
				shadeString = "";
			}

			if (thisWindowDoor.isAWindow()) {
			windowBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisWindowDoor.getConstructionNumber() 
					+ "-" + thisWindowDoor.getFacingString(), "Windows & Doors", windowColumn));
			} else {
				windowBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisWindowDoor.getConstructionNumber(), "Windows & Doors", column));
			}
			thisWindowBTU = thisWindowBTU + (thisWindowUnshadedArea * windowBTUMultiplier);
			thisWindowBTU = thisWindowBTU * thisWindowDoor.getQty();
			
			totalWindowBTU = (int) (totalWindowBTU + thisWindowBTU);
		}

		int thisCeilingArea = 0;
		int totalCeilingBTU = 0;
		double thisCeilingBTU = 0;
		double ceilingBTUMultiplier;

		for (CeilingFloor thisCeiling : ceilingsFloors) {
			thisCeilingArea = (int) thisCeiling.getArea();
			ceilingBTUMultiplier = Double.parseDouble(parser.getDataPoint(thisCeiling.getConstructionNumber(), "Ceilings & Floors", column));

			thisCeilingBTU = thisCeilingArea * ceilingBTUMultiplier;
			totalCeilingBTU = (int) (totalCeilingBTU + thisCeilingBTU);
		}

		int totalSensibleBTU = 0;
		double thisSensibleBTU = 0;
		for (SensibleLoad thisSensibleLoad : sensibleLoads) {
			thisSensibleBTU = thisSensibleLoad.getBtu() * thisSensibleLoad.getQty();
			totalSensibleBTU = (int) (totalSensibleBTU + thisSensibleBTU);
		}

		return totalWallBTU + totalWindowBTU + totalCeilingBTU + totalSensibleBTU;
	}

	private int getWindowColumnNumber(int[] localeData) {
		if (localeData[0] <= 12) {
			return 1;
		} else if (localeData[0] > 12 && localeData[0] <= 17) {
			return 2;
		} else if (localeData[0] > 17 && localeData[0] <= 22) {
			return 3;
		} else if (localeData[0] > 22 && localeData[0] <= 27) {
			return 4;
		} else if (localeData[0] > 27 && localeData[0] <= 32) {
			return 5;
		} else if (localeData[0] > 32) {
			return 6;
		}

		return 0;
	}

	private int getColumnNumber(int[] localeData) {

		if (localeData[0] <= 12) {
			if (localeData[1] == Building.RANGE_LOW) {
				return 1;
			} else if (localeData[1] == Building.RANGE_MEDIUM || localeData[1] == Building.RANGE_HIGH) {
				return 2;
			}
		} else if (localeData[0] > 12 && localeData[0] <= 17) {
			if (localeData[1] == Building.RANGE_LOW) {
				return 3;
			} else if (localeData[1] == Building.RANGE_MEDIUM) {
				return 4;
			} else if (localeData[1] == Building.RANGE_HIGH) {
				return 5;
			}
		} else if (localeData[0] > 17 && localeData[0] <= 22) {
			if (localeData[1] == Building.RANGE_LOW) {
				return 6;
			} else if (localeData[1] == Building.RANGE_MEDIUM) {
				return 7;
			} else if (localeData[1] == Building.RANGE_HIGH) {
				return 8;
			}
		} else if (localeData[0] > 22 && localeData[0] <= 27) {
			if (localeData[1] == Building.RANGE_LOW || localeData[1] == Building.RANGE_MEDIUM) {
				return 9;
			} else if (localeData[1] == Building.RANGE_HIGH) {
				return 10;
			}
		} else if (localeData[0] > 27 && localeData[0] <= 32) {
			return 11;
		} else if (localeData[0] > 32) {
			return 12;
		}

		return 0;
	}

	public Building getParent() {
		return parent;
	}

	public int compareTo(Room another) {
		if (this.id < another.getId())
			return -1;
		else if (this.id > another.getId())
			return 1;
		else
			return 0;
	}

	public int describeContents() { return 0; }

	public void writeToParcel(Parcel dest, int flags) {

		dest.writeLong(id);
		dest.writeString(name);	
		dest.writeInt(zone);

		Wall[] wallsParcelArray = (Wall[]) walls.toArray(new Wall[walls.size()]);
		WindowDoor[] windowsDoorsParcelArray = (WindowDoor[]) windowsDoors.toArray(new WindowDoor[windowsDoors.size()]);
		CeilingFloor[] ceilingsFloorsParcelArray = (CeilingFloor[]) ceilingsFloors.toArray(new CeilingFloor[ceilingsFloors.size()]);
		SensibleLoad[] sensibleLoadsParcelArray = (SensibleLoad[]) sensibleLoads.toArray(new SensibleLoad[sensibleLoads.size()]);

		dest.writeParcelableArray(wallsParcelArray, PARCELABLE_WRITE_RETURN_VALUE);
		dest.writeParcelableArray(windowsDoorsParcelArray, PARCELABLE_WRITE_RETURN_VALUE);
		dest.writeParcelableArray(ceilingsFloorsParcelArray, PARCELABLE_WRITE_RETURN_VALUE);
		dest.writeParcelableArray(sensibleLoadsParcelArray, PARCELABLE_WRITE_RETURN_VALUE);
	}

	public static final Parcelable.Creator<Room> CREATOR = new Parcelable.Creator<Room>() {
		public Room createFromParcel(Parcel in) {
			return new Room(in);
		}

		public Room[] newArray(int size) {
			return new Room[size];
		}
	};

	public Room(Parcel p) {

		this.id = p.readLong();
		this.name = p.readString();
		this.zone = p.readInt();

		Parcelable[] wallsParcelArray = (Parcelable[]) p.readParcelableArray(Wall.class.getClassLoader());
		this.walls = new Vector<Wall>();
		for (Parcelable thisWall : wallsParcelArray) {
			walls.add((Wall) thisWall);
		}

		Parcelable[] windowsDoorsParcelArray = (Parcelable[]) p.readParcelableArray(WindowDoor.class.getClassLoader());
		this.windowsDoors = new Vector<WindowDoor>();
		for (Parcelable thisWindowDoor : windowsDoorsParcelArray) {
			windowsDoors.add((WindowDoor) thisWindowDoor);
		}

		Parcelable[] ceilingsFloorsParcelArray = (Parcelable[]) p.readParcelableArray(CeilingFloor.class.getClassLoader());
		this.ceilingsFloors = new Vector<CeilingFloor>();
		for (Parcelable thisCeilingFloor : ceilingsFloorsParcelArray) {
			ceilingsFloors.add((CeilingFloor) thisCeilingFloor);
		}

		Parcelable[] sensibleLoadsParcelArray = (Parcelable[]) p.readParcelableArray(SensibleLoad.class.getClassLoader());
		this.sensibleLoads = new Vector<SensibleLoad>();
		for (Parcelable thisSensibleLoad : sensibleLoadsParcelArray) {
			sensibleLoads.add((SensibleLoad) thisSensibleLoad);
		}
	}

	public String getBTUString() {
		if (BTUString == null) {
			return "CALC";
		} else {
			return BTUString;
		}
	}
	
	public void setBTUString(String s) {
		BTUString = s;
	}
}